#include <limits.h>

#import <Foundation/NSUserDefaults.h>
#import <Foundation/NSTimer.h>
#import <UIKit/UIKit.h>
#import <UIKit/UIHardware.h>
#import <UIKit/UITouch.h>

#import "PadPanel.h"
#import "QtKey.h"
#import "Tools.h"

@implementation PadPanel

@synthesize delegate;

/*
- (UIButton *)buttonWithFrame:(CGRect)frame
{
	UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
	// [b setRotationBy:90.0];
	[b setFrame:frame];
	[b setShowsTouchWhenHighlighted:YES];
	// [b setBackgroundColor:[UIColor darkGrayColor]];
	// [b setFont:[UIFont systemFontOfSize:36.0]];
	// [b setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
	// [b setBackgroundImage:[UIImage imageNamed:@"Key.png"] forState:UIControlStateNormal];
	// [b setTitle:@"Something" forState:UIControlStateNormal];
	[b addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchDown];
	[b addTarget:self action:@selector(buttonReleased:) forControlEvents:UIControlEventTouchUpInside];
	[b addTarget:self action:@selector(buttonReleased:) forControlEvents:UIControlEventTouchUpOutside];
	return b;
}
*/

- (id)initWithFrame: (CGRect)frame
{
	self = [super initWithFrame: frame];
	
	delegate = nil;
	prevPoint = prevP1 = prevP2 = CGPointZero;
	mouseMoved = leftDragging = rightDragging = NO;
	leftClickTimer = rightClickTimer = nil;
	mouseUpTime = gettimeofday_sec();
	
	[self setBackgroundColor:[UIColor blackColor]];
	[self setMultipleTouchEnabled:YES];
	
	return self;
}

- (void)dealloc
{
	[super dealloc];
}

- (BOOL)canBecomeFirstResponder
{
	return YES;
}

- (void)sendMouseLeftButtonClick:(NSTimer *)timer
{
	[delegate mouseLeftButtonClick];
}

- (void)sendMouseRightButtonClick:(NSTimer *)timer
{
	[delegate mouseRightButtonClick];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
	NSArray *allTouches = [[event allTouches] allObjects];
	
	switch ([allTouches count])	// number of fingers
	{
		case 1:
		{
			begin[0] = [[allTouches objectAtIndex:0] locationInView:self];
			CGPoint p = [[touches anyObject] locationInView: self];
			if (leftClickTimer && [leftClickTimer isValid])	// クリックが発生前ならば、左ドラッグ開始
			{
				[leftClickTimer invalidate];
				[delegate mouseLeftButtonPress];
				leftDragging = YES;
			}
			mouseDownPoint = prevPoint = p;
			mouseDownTime = gettimeofday_sec();
			break;
		}
		case 2:
		{
			begin[0] = [[allTouches objectAtIndex:0] locationInView:self];
			begin[1] = [[allTouches objectAtIndex:1] locationInView:self];
			gesStartTime = gettimeofday_sec();
			
			// クリック発生前ならドラッグ開始
			if (rightClickTimer && [rightClickTimer isValid])
			{
				[rightClickTimer invalidate];
				
				[delegate mouseRightButtonPress];
				rightDragging = YES;
			}
			
			prevP1 = begin[0];
			prevP2 = begin[1];
			break;
		}
		case 3:
			begin[0] = [[allTouches objectAtIndex:0] locationInView:self];
			begin[1] = [[allTouches objectAtIndex:1] locationInView:self];
			begin[2] = [[allTouches objectAtIndex:2] locationInView:self];
			break;
		case 4:
			moving[0] = begin[0] = [[allTouches objectAtIndex:0] locationInView:self];
			moving[1] = begin[1] = [[allTouches objectAtIndex:1] locationInView:self];
			moving[2] = begin[2] = [[allTouches objectAtIndex:2] locationInView:self];
			moving[3] = begin[3] = [[allTouches objectAtIndex:3] locationInView:self];
			break;
		case 5:
			begin[0] = [[allTouches objectAtIndex:0] locationInView:self];
			begin[1] = [[allTouches objectAtIndex:1] locationInView:self];
			begin[2] = [[allTouches objectAtIndex:2] locationInView:self];
			begin[3] = [[allTouches objectAtIndex:3] locationInView:self];
			begin[4] = [[allTouches objectAtIndex:4] locationInView:self];
			break;
		default:
			break;
	}
}

- (void)touchesMoved: (NSSet *)touches withEvent: (UIEvent *)event
{
	NSArray *allTouches = [[event allTouches] allObjects];
	
	switch ([allTouches count])	// number of fingers
	{
		case 1:
		{
			CGSize screen = [self frame].size;
			CGPoint p = [[touches anyObject] locationInView: self];
			
			int x = (int)(p.x / screen.width * USHRT_MAX);
			int y = (int)(p.y / screen.height * USHRT_MAX);
			
			[delegate mouseMoveAbsolute: CGPointMake(x, y)];
			[delegate mouseMoveRelative: CGPointMake(p.x - prevPoint.x, p.y - prevPoint.y)];
			
			prevPoint = p;
			break;
		}
		case 2:
		{
			CGSize screen = [self frame].size;
			
			CGPoint p1 = [[allTouches objectAtIndex:0] locationInView:self];
			CGPoint p2 = [[allTouches objectAtIndex:1] locationInView:self];
			
			int x = (int)(p1.x / screen.width * USHRT_MAX);
			int y = (int)(p1.y / screen.height * USHRT_MAX);
			
			if (rightDragging)
			{
				[delegate mouseMoveAbsolute: CGPointMake(x, y)];
				[delegate mouseMoveRelative: CGPointMake(p1.x - prevP1.x, p1.y - prevP1.y)];
			}
			else	// scroll
			{
				if (1 < (p1.y - prevP1.y) || 1 < (prevP1.x - p1.x))
					[delegate mouseWheel: -1];
				else if (1 < (prevP1.y - p1.y) || 1 < (p1.x - prevP1.x))
					[delegate mouseWheel: 1];
			}
			
			prevP1 = p1;
			prevP2 = p2;
			break;
		}
		case 4:
		{
			moving[0] = [[allTouches objectAtIndex:0] locationInView:self];
			moving[1] = [[allTouches objectAtIndex:1] locationInView:self];
			moving[2] = [[allTouches objectAtIndex:2] locationInView:self];
			moving[3] = [[allTouches objectAtIndex:3] locationInView:self];
			break;
		}
		default:
			break;
	}
}

- (void)touchesEnded: (NSSet *)touches withEvent: (UIEvent *)event
{
	NSArray *allTouches = [[event allTouches] allObjects];
	switch ([allTouches count])	// number of fingers
	{
		case 1:
		{
			end[0] = [[allTouches objectAtIndex:0] locationInView:self];
			CGPoint p = [[touches anyObject] locationInView: self];
			
			double prevMouseUpTime = mouseUpTime;
			mouseUpTime = gettimeofday_sec();
			
			// double click: 前回がクリック(マウス移動ではない == !mouseMoved)で、前回のクリックからCLICK_TIMEOUT[ms]経過しておらず、クリック判定位置である時に
			if (!mouseMoved && (gettimeofday_sec() - prevMouseUpTime) < (CLICK_TIMEOUT / 1000.0) && diffLength(&p, &mouseDownPoint) < SAME_POINT_MARGIN)
			{
				if (!leftDragging)
					[delegate mouseLeftButtonPress];
				[delegate mouseLeftButtonRelease];
				leftDragging = NO;
				[delegate mouseLeftButtonClick];
				return;
			}
			
			// 今回のマウスイベントがカーソル移動だったらYES
			mouseMoved = ((SAME_POINT_MARGIN < diffLength(&p, &mouseDownPoint)) ? YES : NO);
			
			// 左ドラッグ中だった場合、ドラッグを終了
			if (leftDragging)
			{
				[delegate mouseLeftButtonRelease];
				leftDragging = NO;
				return;
			}
			
			// single click
			if (diffLength(&p, &mouseDownPoint) < SAME_POINT_MARGIN && (gettimeofday_sec() - mouseDownTime) < (CLICK_INTERVAL / 1000.0))
			{
				[leftClickTimer release];
				leftClickTimer = [NSTimer scheduledTimerWithTimeInterval: (CLICK_TIMEOUT / 1000.0) target: self selector: @selector(sendMouseLeftButtonClick:) userInfo: nil repeats: NO];
				[leftClickTimer retain];
			}
			break;
		}
		case 2:
		{
			end[0] = [[allTouches objectAtIndex:0] locationInView:self];
			end[1] = [[allTouches objectAtIndex:1] locationInView:self];
			
			// 右ドラッグ中ならリリース
			if (rightDragging)
			{
				[delegate mouseRightButtonRelease];
				rightDragging = NO;
				return;
			}
			
			if (diffLength(&begin[0], &end[0]) < SAME_POINT_MARGIN && diffLength(&begin[1], &end[1]) < SAME_POINT_MARGIN && (gettimeofday_sec() - gesStartTime) < (CLICK_INTERVAL / 1000.0))
			{
				[rightClickTimer release];
				rightClickTimer = [NSTimer scheduledTimerWithTimeInterval: (CLICK_TIMEOUT / 1000.0) target: self selector: @selector(sendMouseRightButtonClick:) userInfo: nil repeats: NO];
				[rightClickTimer retain];
			}
			break;
		}
		case 3:
			end[0] = [[allTouches objectAtIndex:0] locationInView:self];
			end[1] = [[allTouches objectAtIndex:1] locationInView:self];
			end[2] = [[allTouches objectAtIndex:2] locationInView:self];
			if (diffLength(&end[0], &begin[0]) < SAME_POINT_MARGIN)	break;
			if (0 < (end[0].x - begin[0].x))	// swipe to right
				[delegate qtKeyClicked:Key_Forward];
			else
				[delegate qtKeyClicked:Key_Back];
			break;
		case 4:
			end[0] = [[allTouches objectAtIndex:0] locationInView:self];
			end[1] = [[allTouches objectAtIndex:1] locationInView:self];
			end[2] = [[allTouches objectAtIndex:2] locationInView:self];
			end[3] = [[allTouches objectAtIndex:3] locationInView:self];
			if (diffLength(&end[0], &begin[0]) < SAME_POINT_MARGIN)	break;
			if ((end[0].y - begin[0].y) < 0)
			{
				[delegate qtKeyPressed:Key_Meta];
				[delegate qtKeyPressed:'D'];
				[delegate qtKeyReleased:'D'];
				[delegate qtKeyReleased:Key_Meta];
			}
			break;
		case 5:
			end[0] = [[allTouches objectAtIndex:0] locationInView:self];
			end[1] = [[allTouches objectAtIndex:1] locationInView:self];
			end[2] = [[allTouches objectAtIndex:2] locationInView:self];
			end[3] = [[allTouches objectAtIndex:3] locationInView:self];
			end[4] = [[allTouches objectAtIndex:4] locationInView:self];
			break;
		default:
			break;
	}
}

@end
